package com.atguigu.daijia.driver.service.impl;

import com.atguigu.daijia.common.constant.SystemConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.common.util.LocationUtil;
import com.atguigu.daijia.dispatch.client.NewOrderFeignClient;
import com.atguigu.daijia.driver.service.OrderService;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.map.client.MapFeignClient;
import com.atguigu.daijia.model.entity.order.OrderBill;
import com.atguigu.daijia.model.entity.order.OrderInfo;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.CalculateDrivingLineForm;
import com.atguigu.daijia.model.form.order.OrderFeeForm;
import com.atguigu.daijia.model.form.order.StartDriveForm;
import com.atguigu.daijia.model.form.order.UpdateOrderBillForm;
import com.atguigu.daijia.model.form.order.UpdateOrderCartForm;
import com.atguigu.daijia.model.form.payment.ProfitsharingForm;
import com.atguigu.daijia.model.form.rules.FeeRuleRequestForm;
import com.atguigu.daijia.model.form.rules.ProfitsharingRuleRequestForm;
import com.atguigu.daijia.model.form.rules.RewardRuleRequestForm;
import com.atguigu.daijia.model.vo.base.PageVo;
import com.atguigu.daijia.model.vo.map.DrivingLineVo;
import com.atguigu.daijia.model.vo.map.OrderLocationVo;
import com.atguigu.daijia.model.vo.map.OrderServiceLastLocationVo;
import com.atguigu.daijia.model.vo.order.*;
import com.atguigu.daijia.model.vo.rules.FeeRuleResponseVo;
import com.atguigu.daijia.model.vo.rules.ProfitsharingRuleResponseVo;
import com.atguigu.daijia.model.vo.rules.RewardRuleResponseVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.atguigu.daijia.rules.client.FeeRuleFeignClient;
import com.atguigu.daijia.rules.client.ProfitsharingRuleFeignClient;
import com.atguigu.daijia.rules.client.RewardRuleFeignClient;
import lombok.SneakyThrows;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author 谢忠涵7
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;
    @Autowired
    private NewOrderFeignClient newOrderFeignClient;
    @Autowired
    private MapFeignClient mapFeignClient;
    @Autowired
    private LocationFeignClient locationFeignClient;
    @Autowired
    private RewardRuleFeignClient rewardRuleFeignClient;
    @Autowired
    private ProfitsharingRuleFeignClient profitsharingRuleFeignClient;
    @Autowired
    private FeeRuleFeignClient feeRuleFeignClient;
    /**
     * 查询订单状态
     */
    @Override
    public Integer getOrderStatus(Long orderId) {
        Result<Integer> orderStatus = orderInfoFeignClient.getOrderStatus(orderId);
        return orderStatus.getData();
    }

    /**
     * 查询司机新订单数据
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        Result<List<NewOrderDataVo>> result = newOrderFeignClient.findNewOrderQueueData(driverId);

        return result.getData();
    }

    /**
     * 司机抢单
     */
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        Result<Boolean> result = orderInfoFeignClient.robNewOrder(driverId, orderId);
        return result.getData();
    }

    /**
     * 司机端查找当前订单
     */
    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        Result<CurrentOrderInfoVo> result = orderInfoFeignClient.searchDriverCurrentOrder(driverId);
        return result.getData();
    }

    /**
     * 获取订单账单详细信息
     */
    @Override
    public OrderInfoVo getOrderInfo(Long orderId, Long driverId) {
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();
        //比对是否为当前司机的订单数据
        if(!orderInfo.getDriverId().equals(driverId)) {
            throw new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //只有在订单状态为结束服务之后才会生成订单
        if(orderInfo.getStatus() >= OrderStatus.END_SERVICE.getStatus()) {
            OrderBillVo orderBillVo = orderInfoFeignClient.getOrderBillInfo(orderId).getData();
            OrderProfitsharingVo profitsharingVo = orderInfoFeignClient.getOrderProfitsharing(orderId).getData();
            orderInfoVo.setOrderBillVo(orderBillVo);
            orderInfoVo.setOrderProfitsharingVo(profitsharingVo);
        }
        //封装对象
        orderInfoVo.setOrderId(orderId);
        BeanUtils.copyProperties(orderInfo, orderInfoVo);
        return orderInfoVo;
    }

    /**
     * @description: 司机端计算到达乘客地点的最佳路线
     * @author: xiaoxie
     * @date: 2024/10/29 14:39
     * @param: [calculateDrivingLineForm] 位置信息
     * @return: DrivingLineVo
     **/
    @Override
    public DrivingLineVo calculateDrivingLine(CalculateDrivingLineForm calculateDrivingLineForm) {
        Result<DrivingLineVo> drivingLineVoResult = mapFeignClient.calculateDrivingLine(calculateDrivingLineForm);
        return drivingLineVoResult.getData();
    }

    /**
     * 司机到达代驾起始地点更新订单信息
     */
    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        Result<Boolean> result = orderInfoFeignClient.driverArriveStartLocation(orderId, driverId);

        return result.getData();
    }

    /**
     * 更新代驾车辆信息
     */
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        //判断
        // orderInfo有代驾开始位置
        OrderInfo orderInfo = orderInfoFeignClient
                .getOrderInfo(updateOrderCartForm.getOrderId()).getData();

        //司机当前位置
        OrderLocationVo orderLocationVo = locationFeignClient
                .getCacheOrderLocation(updateOrderCartForm.getOrderId()).getData();

        //司机当前位置 和 代驾开始位置距离
        double distance = LocationUtil.getDistance(orderInfo
                        .getStartPointLatitude().doubleValue(),
                orderInfo.getStartPointLongitude().doubleValue(),
                orderLocationVo.getLatitude().doubleValue(),
                orderLocationVo.getLongitude().doubleValue());
        if(distance > SystemConstant.DRIVER_START_LOCATION_DISTION) {
            throw new GuiguException(ResultCodeEnum.DRIVER_START_LOCATION_DISTION_ERROR);
        }
        Result<Boolean> result = orderInfoFeignClient.updateOrderCart(updateOrderCartForm);
        return result.getData();
    }

    /**
     *  开启代驾服务 修改订单信息
     */
    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        Result<Boolean> result = orderInfoFeignClient.startDrive(startDriveForm);
        return result.getData();
    }

    /**
     * 结束代驾服务更新订单账单
     */
    @Override
    @SneakyThrows
    public Boolean endDrive(OrderFeeForm orderFeeForm) {
        //使用 CompletableFuture 优化过程
        //1.先获取订单信息的远程调用
        CompletableFuture<OrderInfo> orderInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderFeeForm.getOrderId());
            return  orderInfoResult.getData();
        });
        //2.防止刷单的远程调用
        //防止刷
        CompletableFuture<OrderServiceLastLocationVo> orderServiceLastLocationVoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return locationFeignClient.getOrderServiceLastLocation(orderFeeForm.getOrderId()).getData();
        });
        //将两个调用合并
        CompletableFuture.allOf(orderInfoCompletableFuture, orderServiceLastLocationVoCompletableFuture).join();
        //获取两个线程执行结果
        //获取订单信息的远程调用
        OrderInfo orderInfo = orderInfoCompletableFuture.get();
        //防止刷单的远程调用
        OrderServiceLastLocationVo orderServiceLastLocationVo = orderServiceLastLocationVoCompletableFuture.get();
        //如果没有远程调用就让它们串行执行即可
        //司机当前位置 距离 结束代驾位置
        double distance = LocationUtil.getDistance(orderInfo.getEndPointLatitude().doubleValue(),
                orderInfo.getEndPointLongitude().doubleValue(),
                orderServiceLastLocationVo.getLatitude().doubleValue(),
                orderServiceLastLocationVo.getLongitude().doubleValue());
        if(distance > SystemConstant.DRIVER_END_LOCATION_DISTION) {
            throw new GuiguException(ResultCodeEnum.DRIVER_END_LOCATION_DISTION_ERROR);
        }
        //2.判断是否为该司机的订单
        if(!orderInfo.getDriverId().equals(orderFeeForm.getDriverId())) {
            throw new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }

        //3.调用接口计算实际里程 使用线程
        CompletableFuture<BigDecimal> realDistanceCompletableFuture = CompletableFuture.supplyAsync(() -> {
           return locationFeignClient
                    .calculateOrderRealDistance(orderFeeForm.getOrderId()).getData();
        });

        //4.调用接口计算实际金额,需要先等计算实际里程的线程执行完之后才会执行
        CompletableFuture<FeeRuleResponseVo> feeRuleResponseVoCompletableFuture =
        realDistanceCompletableFuture.thenApplyAsync((realDistance) -> {
            FeeRuleRequestForm feeRuleRequestForm = new FeeRuleRequestForm();
            feeRuleRequestForm.setDistance(realDistance);
            feeRuleRequestForm.setStartTime(orderInfo.getStartServiceTime());
            Integer waitMinute = Math.abs((int) ((orderInfo.getArriveTime().getTime() - orderInfo.getAcceptTime()
                    .getTime()) / (1000 * 60)));
            feeRuleRequestForm.setWaitMinute(waitMinute);
            Result<FeeRuleResponseVo> feeRuleResponseVoResult = feeRuleFeignClient.calculateOrderFee(feeRuleRequestForm);
            FeeRuleResponseVo feeRuleResponseVo = feeRuleResponseVoResult.getData();
            BigDecimal totalAmount = feeRuleResponseVo.getTotalAmount();
            //总费用应该为 实际金额 + 好处费 + 其他费用(过桥费+停车费+其他费用)
            BigDecimal total = totalAmount.add(orderFeeForm.getTollFee())
                    .add(orderFeeForm.getParkingFee())
                    .add(orderFeeForm.getOtherFee())
                    .add(orderInfo.getFavourFee());
            feeRuleResponseVo.setTotalAmount(total);
            return feeRuleResponseVo;
        });

        //5.调用接口计算系统奖励金额
        // 先执行计算时间段里的订单数量使用的线程
        CompletableFuture<Long> orderNumCompletableFuture = CompletableFuture.supplyAsync(() -> {
            String startTime = new DateTime(orderInfo.getStartServiceTime())
                    .toString("yyyy-MM-dd") + " 00:00:00";
            String endTime = new DateTime(orderInfo.getStartServiceTime())
                    .toString("yyyy-MM-dd") + " 24:00:00";
            return orderInfoFeignClient.getOrderNumByTime(startTime, endTime).getData();
        });

        // 之后在执行计算系统奖励金额的线程
        CompletableFuture<RewardRuleResponseVo> rewardRuleResponseVoCompletableFuture =
        orderNumCompletableFuture.thenApplyAsync((orderNum) -> {
            RewardRuleRequestForm rewardRuleRequestForm = new RewardRuleRequestForm();
            rewardRuleRequestForm.setStartTime(orderInfo.getStartServiceTime());
            rewardRuleRequestForm.setOrderNum(orderNum);
            return rewardRuleFeignClient
                    .calculateOrderRewardFee(rewardRuleRequestForm).getData();
        });

        //6.计算系统分成需要计算系统奖励金额的线程和计算实际金额之后才能执行该线程
        CompletableFuture<ProfitsharingRuleResponseVo> profitsharingRuleResponseVoCompletableFuture =
        feeRuleResponseVoCompletableFuture.thenCombineAsync(orderNumCompletableFuture, (feeRuleResponseVo, orderNum) -> {
            ProfitsharingRuleRequestForm profitsharingRuleRequestForm =
                    new ProfitsharingRuleRequestForm();
            profitsharingRuleRequestForm.setOrderNum(orderNum);
            profitsharingRuleRequestForm.setOrderAmount(feeRuleResponseVo.getTotalAmount());
            return profitsharingRuleFeignClient
                    .calculateOrderProfitsharingFee(profitsharingRuleRequestForm).getData();
        });
        //将所有线程合并之后(为了确保之前的操作线程全部完成)在封装对象
        CompletableFuture.allOf(orderInfoCompletableFuture,orderServiceLastLocationVoCompletableFuture
                               ,realDistanceCompletableFuture,feeRuleResponseVoCompletableFuture
                               ,orderNumCompletableFuture,rewardRuleResponseVoCompletableFuture
                               ,profitsharingRuleResponseVoCompletableFuture).join();
        //取值
        BigDecimal realDistance = realDistanceCompletableFuture.get();
        RewardRuleResponseVo rewardRuleResponseVo = rewardRuleResponseVoCompletableFuture.get();
        FeeRuleResponseVo feeRuleResponseVo = feeRuleResponseVoCompletableFuture.get();
        ProfitsharingRuleResponseVo profitsharingRuleResponseVo = profitsharingRuleResponseVoCompletableFuture.get();
        //7.封装对象
        UpdateOrderBillForm updateOrderBillForm = new UpdateOrderBillForm();
        updateOrderBillForm.setOrderId(orderInfo.getId());
        updateOrderBillForm.setDriverId(orderInfo.getDriverId());
        //路桥费、停车费、其他费用
        updateOrderBillForm.setTollFee(orderFeeForm.getTollFee());
        updateOrderBillForm.setParkingFee(orderFeeForm.getParkingFee());
        updateOrderBillForm.setOtherFee(orderFeeForm.getOtherFee());
        //乘客好处费
        updateOrderBillForm.setFavourFee(orderInfo.getFavourFee());
        //实际里程
        updateOrderBillForm.setRealDistance(realDistance);
        //订单奖励信息
        BeanUtils.copyProperties(rewardRuleResponseVo, updateOrderBillForm);
        //代驾费用信息
        BeanUtils.copyProperties(feeRuleResponseVo, updateOrderBillForm);
        //分账相关信息
        BeanUtils.copyProperties(profitsharingRuleResponseVo, updateOrderBillForm);
        updateOrderBillForm.setProfitsharingRuleId(profitsharingRuleResponseVo.getProfitsharingRuleId());
        Result<Boolean> result = orderInfoFeignClient.endDrive(updateOrderBillForm);
        return true;
    }
    /**
     * 获取司机订单分页列表
     */
    @Override
    public PageVo findDriverOrderPage(Long driverId, Long page, Long limit) {
        return orderInfoFeignClient.findDriverOrderPage(driverId, page, limit).getData();
    }

    /**
     * 司机发送账单信息
     */
    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        return orderInfoFeignClient.sendOrderBillInfo(orderId, driverId).getData();
    }
}
